package com.springboot.uav.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.springboot.uav.dto.LoginDto;
import com.springboot.uav.dto.RegisterDto;
import com.springboot.uav.entity.Result;
import com.springboot.uav.entity.User;
import com.springboot.uav.entity.UserMsg;
import com.springboot.uav.mapper.UserMapper;
import com.springboot.uav.service.UserService;
import com.springboot.uav.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;


/**
 * Created by IntelliJ IDEA.
 * &#064;Author : Zys
 * &#064;create 2024/11/5 14:40
 */
@Service
@Slf4j
@RequiredArgsConstructor//注入必须初始化的值，final
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final JWTUtil jwtUtil;

    private final UserMapper userMapper;

    private final RedisTemplate<String, String> redisTemplate;

    private final EmailUtil emailUtil;

    private final AliOSSUtils aliOSSUtils;


    // 缓存用户 OTP 和生成时间，使用 ConcurrentHashMap 以支持多线程
    public ConcurrentHashMap<String, String> userOtpCache = new ConcurrentHashMap<>();
    public ConcurrentHashMap<String, Long> otpTimestampCache = new ConcurrentHashMap<>();

    /**
     *
     * @param loginDto 要登录的用户
     * @return 登录成功时 返回结果里保存一个token字符串
     */
    @Override
    public Result login(LoginDto loginDto) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", loginDto.getUsername());
        User user = userMapper.selectOne(queryWrapper);

        if(user == null){
            return new Result(400,"用户名有误",null);
        }
        if(!user.getPassword().equals(SHA256Util.sha256(loginDto.getPassword()))){
            return new Result(401,"密码错误",null);
        }
        //登录成功 生成token
        String token = jwtUtil.generateToken(loginDto.getUsername(), user.getUserId());
        redisTemplate.opsForValue().set("token:" + loginDto.getUsername(), token,
                24,
                TimeUnit.HOURS
        );
        UserMsg userMsg = userMapper.getUserMsgById(user.getUserId());
        userMsg.setToken(token);

        return new Result(200,"登录成功",userMsg);

    }

    @Override
    //发送验证码
    public Result send(RegisterDto registerDto) {
        //新增了不值username，还要邮箱，都不能重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", registerDto.getUsername())
                .or().eq("email", registerDto.getEmail());
        User user = userMapper.selectOne(queryWrapper);
        if (Objects.nonNull(user)) {
            return new Result(400,"验证码发送失败 用户已经存在",null);
        }

        //发送邮箱
        String email = registerDto.getEmail();
        String secretKey = "uav"; // 这里可以为每个用户生成一个唯一密钥
        String otp = TotpUtils.generateTotp(secretKey); // 生成动态验证码
        // 将 OTP 和生成时间存入缓存
        userOtpCache.put(email, otp);
        otpTimestampCache.put(email, System.currentTimeMillis()); // 记录生成时间
        log.info("缓存成功");

        // 发送 OTP 到用户邮箱
        emailUtil.sendEmail(email, "快帮帮注册验证码", "您的验证码是: " + otp);
        log.info("发送成功");
        return new Result(200,"验证码发送成功",null);
    }

    @Override
    public Result register(RegisterDto registerDto) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", registerDto.getUsername());
        User user = userMapper.selectOne(queryWrapper);
        if (Objects.nonNull(user)) {
            return new Result(400,"注册失败 用户已经存在",null);
        }
        String email = registerDto.getEmail();//获取邮箱
        String otp=registerDto.getOtp();//获取这个邮箱对应的验证码
        String cachedOtp = userOtpCache.get(email); // 从缓存中获取用户的 OTP
        Long otpTimestamp = otpTimestampCache.get(email); // 获取 OTP 生成时间
        log.info("取出缓存成功");

        // 验证 OTP
        if (cachedOtp != null && otpTimestamp != null) {
            // 检查 OTP 是否在 600 秒内生成
            if (System.currentTimeMillis() - otpTimestamp <= 60000) {
                if (cachedOtp.equals(otp)) { // 验证通过
                    userOtpCache.remove(email); // 验证通过后，清除缓存
                    otpTimestampCache.remove(email);
                    log.info("验证成功");
                    User saveUser = new User().setUsername(registerDto.getUsername())
                            .setPassword(SHA256Util.sha256(registerDto.getPassword()))
                            .setEmail(registerDto.getEmail());
                    userMapper.insert(saveUser);
                    return new Result(200,"注册成功",null);// 返回成功响应
                } else {
                    return new Result(401,"验证码错误",null);// 验证失败
                }
            } else {
                return new Result(402,"验证码已过期请重新获取验证码",null);// 过期验证
            }
        }
        return new Result(403,"验证码为空，请先获取验证码",null);// 需要先请求验证码
    }

    @Override
    public boolean updatePhoneNumber(Integer userId, String newPhoneNumber) {
        User user = new User();
        user.setPhoneNumber(newPhoneNumber);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", userId);
        log.info("更新号码成功");
        return this.update(user, updateWrapper);
    }

    @Override
    public String getPhoneNumber(Integer userId) {
        User user = getById(userId);
        if (user != null) {
            return user.getPhoneNumber();
        }
        return null;
    }

    @Override
    public Result updateAvatar(String username, MultipartFile file) {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        try {
            String url = aliOSSUtils.upload(file);
            System.out.println(url);
            User user = new User();
            user.setAvatar(url);
            updateWrapper.eq("username",username);
            userMapper.update(user,updateWrapper);
            return new Result(200,"更新成功",url);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public boolean updateSex(Integer userId, Integer sex) {
        User user = new User();
        user.setSex(sex);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", userId);
        return this.update(user, updateWrapper);
    }

    @Override
    public Integer getSexById(Integer userId) {
        User user = this.getById(userId);
        return user != null ? user.getSex() : null;
    }

    @Override
    public boolean updateNickname(Integer userId, String newNickname) {

        int rows = userMapper.updateNicknameById(userId, newNickname);
        return rows > 0;
    }

    @Override
    public boolean updatePassword(Integer userId, String oldPassword, String newPassword) {
        User user = userMapper.selectById(userId);
        if (user != null && user.getPassword().equals(oldPassword)) {
            int rows = userMapper.updatePasswordById(userId, newPassword);
            return rows > 0;
        }
        return false;
    }

    @Override
    public String getNickname(Integer userId) {
        User user = userMapper.selectById(userId);
        return user != null ? user.getNickname() : null;
    }

    @Override
    public boolean checkPassword(Integer userId, String password) {

        User user = userMapper.selectById(userId);

        if (user != null) {

            String storedPassword = user.getPassword();
            return storedPassword.equals(password);
        }
        return false;
    }


}
